package com.likuicat.picture_ddd.application.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.likuicat.picture_ddd.infrastructure.exception.BusinessException;
import com.likuicat.picture_ddd.infrastructure.exception.ErrorCode;
import com.likuicat.picture_ddd.infrastructure.exception.ThrowUtils;
import com.likuicat.picture_ddd.interfaces.dto.space.analyze.*;
import com.likuicat.picture_ddd.domain.picture.entity.Picture;
import com.likuicat.picture_ddd.domain.space.entity.Space;
import com.likuicat.picture_ddd.domain.user.entity.User;
import com.likuicat.picture_ddd.interfaces.vo.space.analyze.*;
import com.likuicat.picture_ddd.application.service.PictureApplicationService;
import com.likuicat.picture_ddd.application.service.SpaceAnalyzeApplicationService;
import com.likuicat.picture_ddd.application.service.SpaceApplicationService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author fc3379757631
 * @description 针对表【space(空间)】的数据库操作Service实现
 * @createDate 2025-05-06 16:38:48
 */
@Service
@Slf4j
public class SpaceAnalyzeApplicationServiceImpl implements SpaceAnalyzeApplicationService {

    @Resource
    private SpaceApplicationService spaceApplicationService;

    @Resource
    private PictureApplicationService pictureApplicationService;

    /**
     * 校验空间分析权限
     * @param spaceAnalyzeRequest
     * @param loginUser
     */
    private void checkSpaceAnalyzeAuth(SpaceAnalyzeRequest spaceAnalyzeRequest,User loginUser) {
        Long spaceId = spaceAnalyzeRequest.getSpaceId();
        boolean queryPublic = spaceAnalyzeRequest.isQueryPublic();
        boolean queryAll = spaceAnalyzeRequest.isQueryAll();
        //仅管理员可查看
        if(queryAll || queryPublic) {
            ThrowUtils.throwIf(!loginUser.isAdmin(), ErrorCode.NO_AUTH_ERROR);
            return;
        }
        //仅用户和管理员可查看特定空间
        if(spaceId != null) {
            Space space = spaceApplicationService.getById(spaceId);
            ThrowUtils.throwIf(!space.getUserId().equals(loginUser.getId()), ErrorCode.NO_AUTH_ERROR,"空间不存在");
            //校验空间权限
            spaceApplicationService.checkSpaceAuth(loginUser,space);
            return;
        }
        throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
    }

    /**
     * 根据分析范围填充请求对象
     * @param spaceAnalyzeRequest
     * @param queryWrapper
     */
    private static void fillAnalyzeQueryWrapper(SpaceAnalyzeRequest spaceAnalyzeRequest,QueryWrapper<Picture> queryWrapper) {
        Long spaceId = spaceAnalyzeRequest.getSpaceId();
        boolean queryPublic = spaceAnalyzeRequest.isQueryPublic();
        boolean queryAll = spaceAnalyzeRequest.isQueryAll();
        //管理员查询所有空间使用情况
        if(queryAll){
            return;
        }
        //管理员查询公共空间使用情况
        if(queryPublic){
            queryWrapper.isNull("spaceId");
            return;
        }
        //管理员/本人查询特定空间使用情况
        if(spaceId != null){
            queryWrapper.eq("spaceId", spaceId);
            return;
        }
        throw new BusinessException(ErrorCode.PARAMS_ERROR,"未查询指定范围数据");
    }

    @Override
    public SpaceUsageAnalyzeResponse getSpaceUsageAnalyze(SpaceUsageAnalyzeRequest spaceUsageAnalyzeRequest, User loginUser) {
        ThrowUtils.throwIf(spaceUsageAnalyzeRequest == null,ErrorCode.NOT_FOUND_ERROR);
        if(spaceUsageAnalyzeRequest.isQueryAll() || spaceUsageAnalyzeRequest.isQueryPublic()){
            //管理员查询全部/公共空间
            // 1.校验权限
            ThrowUtils.throwIf(!loginUser.isAdmin(),ErrorCode.NO_AUTH_ERROR,"无权访问空间");
            // 2.查询所有图片
            QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("picSize");
            if(spaceUsageAnalyzeRequest.isQueryAll()){
                //查询公共空间
                queryWrapper.isNull("spaceId");
            }
            //selectObjs 只返回第一个值（picSize）,减少查询数据的体积
            List<Object> objects = pictureApplicationService.getBaseMapper().selectObjs(queryWrapper);
            //返回所有图片体积之和
            long usedSize = objects.stream().mapToLong(picture -> picture instanceof Long ? (Long) picture : 0).sum();
            long usedCount = objects.size();
            // 3.封装返回结果
            SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
            spaceUsageAnalyzeResponse.setUsedSize(usedSize);
            spaceUsageAnalyzeResponse.setUsedCount(usedCount);
            //公共图库无上限无比例
            spaceUsageAnalyzeResponse.setMaxSize(null);
            spaceUsageAnalyzeResponse.setSizeUsageRatio(null);
            spaceUsageAnalyzeResponse.setMaxCount(null);
            spaceUsageAnalyzeResponse.setCountUsageRatio(null);
            return spaceUsageAnalyzeResponse;
        }else{
            //管理员/本人查询特定空间
            // 1.校验权限
            Space space = spaceApplicationService.getById(spaceUsageAnalyzeRequest.getSpaceId());
            if(!loginUser.isAdmin() && !space.getUserId().equals(loginUser.getId())){
                throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"无权访问空间");
            }
            // 2.查询所有图片总体积
            Long maxSize = space.getMaxSize();
            Long maxCount = space.getMaxCount();
            Long totalSize = space.getTotalSize();
            Long totalCount = space.getTotalCount();
            // 3.封装返回结果
            SpaceUsageAnalyzeResponse spaceUsageAnalyzeResponse = new SpaceUsageAnalyzeResponse();
            spaceUsageAnalyzeResponse.setUsedSize(totalSize);
            spaceUsageAnalyzeResponse.setUsedCount(totalCount);
            spaceUsageAnalyzeResponse.setMaxSize(maxSize);
            spaceUsageAnalyzeResponse.setMaxCount(maxCount);
            double sizeUsageRatio = NumberUtil.round(totalSize * 100.0 / maxSize, 2).doubleValue(); //保留两位小数
            spaceUsageAnalyzeResponse.setSizeUsageRatio(sizeUsageRatio);
            double countUsageRatio = NumberUtil.round(totalCount * 100.0 / maxCount, 2).doubleValue();
            spaceUsageAnalyzeResponse.setCountUsageRatio(countUsageRatio);
            return spaceUsageAnalyzeResponse;
        }
    }

    @Override
    public List<SpaceCategoryAnalyzeResponse> getSpaceCategoryAnalyzeList(SpaceCategoryAnalyzeRequest request, User loginUser) {
        // 1.校验权限
        ThrowUtils.throwIf(request == null,ErrorCode.NOT_FOUND_ERROR);
        // 2.构造条件
        checkSpaceAnalyzeAuth(request,loginUser);
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(request,queryWrapper);
        queryWrapper.select("category AS category",
                "COUNT(*) AS count",
                "SUM(picSize) AS totalSize")
                .groupBy("category");
        // 3.查询数据库 select category, count(*), sum(picSize) from picture;
        List<Map<String, Object>> maps = pictureApplicationService.getBaseMapper().selectMaps(queryWrapper);
        log.info("maps = {}",maps);
        // 4.返回
        return maps.stream().map(result -> {
            String category = result.get("category") != null ? (String) result.get("category") : "未分类";
            Long count = (Long) result.get("count");
            BigDecimal bigDecimalTotalSize = (BigDecimal) result.get("totalSize");
            Long totalSize = bigDecimalTotalSize.longValue();
            return new SpaceCategoryAnalyzeResponse(category, count, totalSize);
        }).collect(Collectors.toList());
    }

    @Override
    public List<SpaceTagAnalyzeResponse> getSpaceTagAnalyzeList(SpaceTagAnalyzeRequest request, User loginUser) {
        // 1.校验参数
        ThrowUtils.throwIf(request == null,ErrorCode.NOT_FOUND_ERROR);
        // 2.校验权限
        checkSpaceAnalyzeAuth(request,loginUser);
        // 3.构造条件
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(request,queryWrapper);
        queryWrapper.select("tags");
        // 4.查询数据库
        List<Object> objects = pictureApplicationService.getBaseMapper().selectObjs(queryWrapper);
        List<String> tagsList = objects
                .stream()
                .filter(ObjUtil::isNotNull)
                .map(Object::toString)
                .collect(Collectors.toList());
        // 5。将查询出的tags拆解为一个一个的字符串存入数组并统计
        // flot 将一个流中的每个元素转换为另一个流，然后将所有这些流"扁平化"（flatten）为一个单一的流。
        Map<String, Long> tagsGroupingList = tagsList.stream()
                .flatMap(tags -> CollUtil.toList(tags).stream())
                .collect(Collectors.groupingBy(tag -> tag, Collectors.counting()));

        return tagsGroupingList.entrySet().stream()
                .sorted((e1,e2) -> Long.compare(e2.getValue(), e1.getValue())) //降序
                .map(entry -> new SpaceTagAnalyzeResponse(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList());
    }

    @Override
    public List<SpaceSizeAnalyzeResponse> getSpaceSizeAnalyzeList(SpaceSizeAnalyzeRequest request, User loginUser) {
        // 1.校验参数
        ThrowUtils.throwIf(request == null,ErrorCode.NOT_FOUND_ERROR);
        // 2.校验权限
        checkSpaceAnalyzeAuth(request,loginUser);
        // 3.构造参数
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        fillAnalyzeQueryWrapper(request,queryWrapper);
        queryWrapper.select("picSize");
        // 4.查询数据库
        List<Long> pictureSizeList = pictureApplicationService.getBaseMapper().selectObjs(queryWrapper)
                .stream()
                .map(s -> (Long) s)
                .collect(Collectors.toList());
        // 5.分别统计不同大小的图片
        Map<String, Long> sizeRange = new LinkedHashMap<>();//有序map
        sizeRange.put("<100KB",pictureSizeList.stream().filter(size -> size < 1024 * 100).count());
        sizeRange.put("100KB-500KB",pictureSizeList.stream().filter(size -> size >= 1024 * 100 && size < 1024 * 500).count());
        sizeRange.put("500KB-1M",pictureSizeList.stream().filter(size -> size >= 1024 * 500 && size < 1024 * 1024).count());
        sizeRange.put(">1M",pictureSizeList.stream().filter(size -> size >= 1024 * 1024).count());

        // 6.返回
        return sizeRange.entrySet()
                .stream()
                .map(entry -> new SpaceSizeAnalyzeResponse(entry.getKey(),entry.getValue()))
                .collect(Collectors.toList());
    }

    @Override
    public List<SpaceUserAnalyzeResponse> getSpaceUserAnalyzeList(SpaceUserAnalyzeRequest request, User loginUser) {
        // 1.校验参数
        ThrowUtils.throwIf(request == null,ErrorCode.NOT_FOUND_ERROR);
        // 2.校验权限
        checkSpaceAnalyzeAuth(request,loginUser);
        // 3.构造参数
        QueryWrapper<Picture> queryWrapper = new QueryWrapper<>();
        Long userId = request.getUserId();
        queryWrapper.eq(ObjUtil.isNotEmpty(userId),"userId",userId);
        fillAnalyzeQueryWrapper(request,queryWrapper);
        // 分析维度：天 周 月
        String timeDimension = request.getTimeDimension();
        switch (timeDimension){
            case "day":
                queryWrapper.select("DATE_FORMAT(createTime,'%Y-%m-%d') as period","COUNT(*) as count");
                break;
            case "week":
                queryWrapper.select("YEARWEEK(createTime) as period","COUNT(*) as count");
                break;
            case "month":
                queryWrapper.select("DATE_FORMAT(createTime,'%Y-%m') as period","COUNT(*) as count");
                break;
            default:
                throw new BusinessException(ErrorCode.PARAMS_ERROR,"不支持的时间维度");
        }
        // 分组与排序
        queryWrapper.groupBy("period").orderByAsc("period");
        // 4.查询数据库
        List<Map<String, Object>> maps = pictureApplicationService.getBaseMapper().selectMaps(queryWrapper);
        log.info("maps = {}",maps);
        // 5.封装结果返回
        return maps.stream()
                .map(result -> {
                    String period = result.get("period").toString();
                    Long count = ((Number) result.get("count")).longValue();
                    return new SpaceUserAnalyzeResponse(period, count);
                }).collect(Collectors.toList());
    }

    @Override
    public List<Space> getSpaceRankAnalyzeList(SpaceRankAnalyzeRequest request, User loginUser) {
        // 1.校验参数
        ThrowUtils.throwIf(request == null,ErrorCode.NOT_FOUND_ERROR);
        // 2.校验权限
        ThrowUtils.throwIf(!loginUser.isAdmin(),ErrorCode.NO_AUTH_ERROR,"非管理员无权查看空间排行");
        // 3.构造条件
        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id","spaceName","userId","totalSize")
                .orderByDesc("totalSize")
                .last("limit " + request.getTopN()); //取前N名
        // 4.查询数据库并返回
        return spaceApplicationService.list(queryWrapper);
    }
}




